Shader "Hidden/Mirror/BlurDoF"
{
    Properties { }
    SubShader
    {
        Tags { "RenderPipeline"="UniversalPipeline" "RenderType"="Opaque" }
        ZWrite Off Cull Off ZTest Always

        Pass
        {
            Name "KawasePass0"
            HLSLPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag
            #pragma multi_compile _ _DOF_ON
            #pragma shader_feature _PASS_ODD

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            TEXTURE2D_X(_MainTex);        SAMPLER(sampler_MainTex);
            TEXTURE2D_X_FLOAT(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture);

            float4 _PixelSize;   // (1/w,1/h,0,0)
            float  _Radius;
            float  _FocusDistance;
            float  _FocusRange;
            float  _DoFIntensity;

            struct VIn  { float4 pos: POSITION; };
            struct VOut { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; };

            VOut Vert (VIn i)
            {
                VOut o;
                o.pos = GetFullScreenTriangleVertexPosition(i.pos);
                o.uv  = GetFullScreenTriangleTexCoord(i.pos);
                return o;
            }

            float Depth01(float2 uv) {
                #if defined(SHADER_API_MOBILE)
                    float d = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r;
                #else
                    float d = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r;
                #endif
                return d;
            }

            float CocFactor(float2 uv)
            {
                #if _DOF_ON
                    float d01 = Depth01(uv);
                    float eye = LinearEyeDepth(d01, _ZBufferParams);
                    float coc = saturate(abs(eye - _FocusDistance) / max(1e-4, _FocusRange));
                    return saturate(coc * _DoFIntensity);
                #else
                    return 1.0;
                #endif
            }

            float4 Frag (VOut i) : SV_Target
            {
                float coc = CocFactor(i.uv);
                float2 off = _PixelSize.xy * (_Radius * coc);

                #if defined(_PASS_ODD)
                    float2 o1 = float2( 1,  1) * off;
                    float2 o2 = float2(-1,  1) * off;
                    float2 o3 = float2( 1, -1) * off;
                    float2 o4 = float2(-1, -1) * off;
                #else
                    float2 o1 = float2( 1,  0) * off;
                    float2 o2 = float2(-1,  0) * off;
                    float2 o3 = float2( 0,  1) * off;
                    float2 o4 = float2( 0, -1) * off;
                #endif

                float4 s = 0;
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o1);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o2);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o3);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o4);
                s *= 0.25;

                return s;
            }
            ENDHLSL
        }

        Pass
        {
            Name "KawasePass1"
            HLSLPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag
            #pragma multi_compile _ _DOF_ON
            #pragma shader_feature _PASS_ODD

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            TEXTURE2D_X(_MainTex);        SAMPLER(sampler_MainTex);
            TEXTURE2D_X_FLOAT(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture);

            float4 _PixelSize;
            float  _Radius;
            float  _FocusDistance;
            float  _FocusRange;
            float  _DoFIntensity;

            struct VIn  { float4 pos: POSITION; };
            struct VOut { float4 pos: SV_POSITION; float2 uv: TEXCOORD0; };

            VOut Vert (VIn i)
            {
                VOut o;
                o.pos = GetFullScreenTriangleVertexPosition(i.pos);
                o.uv  = GetFullScreenTriangleTexCoord(i.pos);
                return o;
            }

            float Depth01(float2 uv) {
                float d = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, uv).r;
                return d;
            }

            float CocFactor(float2 uv)
            {
                #if _DOF_ON
                    float d01 = Depth01(uv);
                    float eye = LinearEyeDepth(d01, _ZBufferParams);
                    float coc = saturate(abs(eye - _FocusDistance) / max(1e-4, _FocusRange));
                    return saturate(coc * _DoFIntensity);
                #else
                    return 1.0;
                #endif
            }

            float4 Frag (VOut i) : SV_Target
            {
                float coc = CocFactor(i.uv);
                float2 off = _PixelSize.xy * (_Radius * coc);

                #if defined(_PASS_ODD)
                    float2 o1 = float2( 1,  1) * off;
                    float2 o2 = float2(-1,  1) * off;
                    float2 o3 = float2( 1, -1) * off;
                    float2 o4 = float2(-1, -1) * off;
                #else
                    float2 o1 = float2( 1,  0) * off;
                    float2 o2 = float2(-1,  0) * off;
                    float2 o3 = float2( 0,  1) * off;
                    float2 o4 = float2( 0, -1) * off;
                #endif

                float4 s = 0;
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o1);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o2);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o3);
                s += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, i.uv + o4);
                s *= 0.25;

                return s;
            }
            ENDHLSL
        }
    }
    Fallback Off
}
